/*
	BitBuffer.c

	Digital STREAM Technology, Inc.
*/


/********************************************************************
 *
 * DHL_bitbuffer.c - Utility for extracting bits from a buffer
 *
 * Copyright 1997-2002 TeraLogic, Inc.
 * All Rights Reserved
 *
 * $Id: //suprahd/releases/suprahd_239/suprahd_zTVApp660_239/drivers/transport/bitbuffer.c#1 $
 * $Revision: #1 $
 * $DateTime: 2006/06/05 14:53:58 $
 * $Change: 45890 $
 * $Author: catherine.lee $
 * 
 ********************************************************************/

#include "DHL_OSAL.h"
#include "DHL_bitbuffer.h"


/* Static Tables */
static const UINT32 bitMaskTable[] = {
	0x00000000,0x00000001,0x00000003,0x00000007,0x0000000F,0x0000001F,0x0000003F,0x0000007F,
	0x000000FF,0x000001FF,0x000003FF,0x000007FF,0x00000FFF,0x00001FFF,0x00003FFF,0x00007FFF,
	0x0000FFFF,0x0001FFFF,0x0003FFFF,0x0007FFFF,0x000FFFFF,0x001FFFFF,0x003FFFFF,0x007FFFFF,
	0x00FFFFFF,0x01FFFFFF,0x03FFFFFF,0x07FFFFFF,0x0FFFFFFF,0x1FFFFFFF,0x3FFFFFFF,0x7FFFFFFF,
	0xFFFFFFFF
};

static const UINT8 shiftTable1[] = {8,1,2,3,4,5,6,7};
static const UINT8 shiftTable2[] = {0,7,6,5,4,3,2,1};



/*=========================================================================
ErrCode bitBufferCreate (bitBufferPtr_t *instance, UINT8 *buffer, UINT32 bufSize)

	*instance:	bitBuffer instance passed back to caller.
	*buffer:	pointer to a byte buffer.
	bufSize:	size of the buffer (in bytes).

Creates a bitBuffer.  After creation, the bitBufferGetBits() function can
be called to extract bits.
=========================================================================*/
ErrCode bitBufferCreate (bitBufferPtr_t *instance, UINT8 *buffer, UINT32 bufSize)
{
	bitBufferPtr_t	bitBufferPtr;
	

	/* create bitBuffer structure */
	bitBufferPtr = (bitBufferPtr_t)OS_Calloc(1,sizeof(bitBuffer_t));
	if (bitBufferPtr == NULL) {
		return (DHL_FAIL_OUT_OF_MEMORY);
	}

	/* Initialize */
	bitBufferPtr->buffer = buffer;
	bitBufferPtr->bufSize = bufSize;
	bitBufferPtr->bitOffset = 0;

	/* pass instance to user */
	*instance = bitBufferPtr;

	return (noError);
}


/*=========================================================================
ErrCode bitBufferDestroy (bitBufferPtr_t instance)

	instance:	bitBuffer instance.

Deletes the bitBuffer.  DOES NOT free the buffer passed by the user in the
function bitBufferCreate()!!
=========================================================================*/
ErrCode bitBufferDestroy (bitBufferPtr_t instance)
{
	OS_Free(&instance);
	return (noError);
}

/*=========================================================================
void bitBufferInitialize (bitBufferPtr_t bitBufferPtr, UINT8 *buffer, UINT32 bufSize)

	instance:	bitBuffer instance passed.
	*buffer:	pointer to a byte buffer.
	bufSize:	size of the buffer (in bytes).

Initializes the bitBuffer.  After initialization, the bitBufferGetBits() function can
be called to extract bits.
=========================================================================*/
void bitBufferInitialize (bitBufferPtr_t bitBufferPtr, UINT8 *buffer, UINT32 bufSize)
{
	/* Initialize */
	bitBufferPtr->buffer = buffer;
	bitBufferPtr->bufSize = bufSize;
	bitBufferPtr->bitOffset = 0;
	bitBufferPtr->overrunError = 0;

	return;
}


/*=========================================================================
UINT32 bitBufferGetBits (bitBufferPtr_t bitBufferPtr, UINT8 numberOfBits)

	bitBufferPtr:	bitBuffer instance.
	numberOfBits:	number of bits to be read from bitBuffer.

Extracts the specified number of bits from the bitBuffer.  The number of
bits must be less than or equal to 32.  If more bits are requested than
are present in the bitBuffer, the overrunError flag is set.
=========================================================================*/
UINT32 bitBufferGetBits (bitBufferPtr_t bitBufferPtr, UINT8 numberOfBits)
{
	UINT32			returnBits = 0;
	UINT8			bitIndex;
	UINT8			newBitIndexDiv8,newBitIndexMod8;
	UINT8			readByteCount;
	UINT8			*p;
	UINT8			i;


	DHL_ASSERT((numberOfBits <= 32), "numberOfBits > 32");

	if (numberOfBits > (8*bitBufferPtr->bufSize - bitBufferPtr->bitOffset)) {
		if (bitBufferPtr->overrunError < 3)
		OS_DbgPrintf("!! bitBuffer Overrun getting %d bits. errcount %d, offset %u:%u among buf %u\n",
				numberOfBits, bitBufferPtr->overrunError+1, 
				bitBufferPtr->bitOffset/8, bitBufferPtr->bitOffset%8, 
				bitBufferPtr->bufSize);
		bitBufferPtr->overrunError++;
		bitBufferPtr->bitOffset = 8*bitBufferPtr->bufSize;
		returnBits = 0;
		goto GetBitsReturn;
	}

	bitIndex = bitBufferPtr->bitOffset & 0x07;
	newBitIndexDiv8 = (bitIndex+numberOfBits) >> 3;
	newBitIndexMod8 = (bitIndex+numberOfBits) & 0x07;
	readByteCount = newBitIndexDiv8 + (newBitIndexMod8 ? 1:0);

	p = bitBufferPtr->buffer + (bitBufferPtr->bitOffset >> 3);
	
	/* copy first byte */
	returnBits = *p++;
	if (readByteCount < 2) {
		/* shift bits right */
		returnBits = returnBits >> shiftTable2[newBitIndexMod8];
	}
	else { /* more bytes */
		for (i=0; i < readByteCount-2; i++) {
			/* just copying 'middle' bytes */
			returnBits = (returnBits << 8) | *p++;
		}		
		/* copy last byte */
		returnBits = (returnBits << shiftTable1[newBitIndexMod8]) | ((*p) >> shiftTable2[newBitIndexMod8]);
	}

	returnBits &= bitMaskTable[numberOfBits];
	bitBufferPtr->bitOffset += numberOfBits;

GetBitsReturn:
	return (returnBits);
}


/*=========================================================================
void bitBufferSkipBits (bitBufferPtr_t bitBufferPtr, UINT16 numberOfBits)

	bitBufferPtr:	bitBuffer instance.
	numberOfBits:	number of bits to be skipped.

Skips the specified number of bits in the bitBuffer.  This operation is
faster than extracting bits and can be used when a bit field is ignored.
=========================================================================*/
void bitBufferSkipBits (bitBufferPtr_t bitBufferPtr, UINT16 numberOfBits)
{
	bitBufferPtr->bitOffset += numberOfBits;
	if (8*bitBufferPtr->bufSize < bitBufferPtr->bitOffset) {
		bitBufferPtr->overrunError = TRUE;
	}
	return;
}


/*=========================================================================
UINT8* bitBufferGetBytePointer (INT32 instance)

	bitBufferPtr:		bitBuffer instance.

Returns a pointer to the current byte offset.
=========================================================================*/
UINT8* bitBufferGetBytePointer (bitBufferPtr_t bitBufferPtr)
{
	return (bitBufferPtr->buffer + (bitBufferPtr->bitOffset >> 3));
}


/*=========================================================================
BOOLEAN bitBufferCheckError (INT32 instance)

	bitBufferPtr_t:		bitBuffer instance.

Returns 'TRUE' if the bitBuffer is in an overrun error state.
=========================================================================*/
BOOLEAN bitBufferCheckError (bitBufferPtr_t bitBufferPtr)
{
	return (bitBufferPtr->overrunError ? TRUE : FALSE);
}



